using System.Collections.Generic;
using System.IO;
using HQLAddin.Intellisense;
using HQLAddin.Tests.SnapshotUtils;
using HqlIntellisense;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Moq;
using NUnit.Framework;
using SharpTestsEx;

namespace HQLAddin.Tests.Intellisense.CompletionSourceTests
{
	[TestFixture]
	public class CompletionSourceTests
	{
		private static readonly string[] ExampleForIntellisense
			= File.ReadAllLines("examples\\example-for-intellisense.xml");

		private static void IsProperlyCallingToCodeComplete(int snapshotPointPosition, string expectedStart)
		{
			ITextSnapshot snapshot = SnapshotUtil.CreateSnapshot(ExampleForIntellisense);
			var buffer = new Mock<ITextBuffer>();
			var session = new Mock<ICompletionSession>();
			buffer.Setup(b => b.CurrentSnapshot).Returns(snapshot);

			session.Setup(s => s.GetTriggerPoint(buffer.Object).GetPoint(snapshot))
				.Returns(SnapshotUtil.CreateSnapshotPoint(snapshot, snapshotPointPosition));

			var codeAssist = new Mock<IHQLCodeAssist>();


			codeAssist.Setup(ca => ca.CodeComplete(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<IHQLCompletionRequestor>()))
				.Callback<string, int, IHQLCompletionRequestor>(
					(query, position, requestor) => query.Substring(position).Should().StartWith(expectedStart));

			var completionSource = new CompletionSource(buffer.Object, codeAssist.Object,
			                                            new Mock<ITextStructureNavigatorSelectorService>().Object, null);

			completionSource.AugmentCompletionSession(session.Object, new List<CompletionSet>());

			codeAssist.Verify(ca => ca.CodeComplete(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<IHQLCompletionRequestor>()),
			                  Times.Once());
		}

		[Test]
		public void CodeCompleteIsProperlyCalledCase1()
		{
			IsProperlyCallingToCodeComplete(345, "Foo ");
		}

		[Test]
		public void CodeCompleteIsProperlyCalledCase2()
		{
			IsProperlyCallingToCodeComplete(359, "where f.id = 1");
		}

		[Test]
		public void CodeCompleteIsProperlyCalledCase3()
		{
			IsProperlyCallingToCodeComplete(554, "Foo where where");
		}

		[Test]
		public void CodeCompleteIsProperlyCalledCase4()
		{
			IsProperlyCallingToCodeComplete(639, "where where f.id");
		}

		[Test]
		public void WhenCallingOutsideQueryTagsThenDoNothing()
		{
			ITextSnapshot snapshot = SnapshotUtil.CreateSnapshot(ExampleForIntellisense);
			var buffer = new Mock<ITextBuffer>();
			var session = new Mock<ICompletionSession>();
			buffer.Setup(b => b.CurrentSnapshot).Returns(snapshot);

			session.Setup(s => s.GetTriggerPoint(buffer.Object).GetPoint(snapshot))
				.Returns(SnapshotUtil.CreateSnapshotPoint(snapshot, 385));

			var codeAssist = new Mock<IHQLCodeAssist>();



			var completionSource = new CompletionSource(buffer.Object, codeAssist.Object,
														new Mock<ITextStructureNavigatorSelectorService>().Object, null);

			var completionSet = new CompletionSet();
			var completionSets = new List<CompletionSet>{completionSet};
			completionSource.AugmentCompletionSession(session.Object, completionSets);

			completionSets.Should().Contain(completionSet);
			codeAssist.Verify(ca => ca.CodeComplete(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<IHQLCompletionRequestor>()),
							  Times.Never());
		}


		[Test]
		public void WhenCallingOnEmptyQueryTagsThenDoNothing()
		{
			ITextSnapshot snapshot = SnapshotUtil.CreateSnapshot(ExampleForIntellisense);
			var buffer = new Mock<ITextBuffer>();
			var session = new Mock<ICompletionSession>();
			buffer.Setup(b => b.CurrentSnapshot).Returns(snapshot);

			session.Setup(s => s.GetTriggerPoint(buffer.Object).GetPoint(snapshot))
				.Returns(SnapshotUtil.CreateSnapshotPoint(snapshot, 857));

			var codeAssist = new Mock<IHQLCodeAssist>();



			var completionSource = new CompletionSource(buffer.Object, codeAssist.Object,
														new Mock<ITextStructureNavigatorSelectorService>().Object, null);

			var completionSet = new CompletionSet();
			var completionSets = new List<CompletionSet> { completionSet };
			completionSource.AugmentCompletionSession(session.Object, completionSets);

			completionSets.Should().Contain(completionSet);
			codeAssist.Verify(ca => ca.CodeComplete(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<IHQLCompletionRequestor>()),
							  Times.Never());
		}

		//[Test]
		//public void WhenCursorHasNoWordInFrontThenTrackingSpanStartInSamePositionAndHas0Lenght()
		//{
		//    var snapshot = SnapshotUtil.CreateSnapshot(ExampleForIntellisense);
		//    var buffer = new Mock<ITextBuffer>();
		//    var session = new Mock<ICompletionSession>();
		//    buffer.Setup(b => b.CurrentSnapshot).Returns(snapshot);
		//    session.Setup(s => s.TextView.Caret.Position)
		//        .Returns(new CaretPosition(new VirtualSnapshotPoint(snapshot, 819), new Mock<IMappingPoint>().Object, PositionAffinity.Successor));

		//    session.Setup(s => s.GetTriggerPoint(buffer.Object).GetPoint(snapshot))
		//        .Returns(SnapshotUtil.CreateSnapshotPoint(snapshot, 819)); // <---Important arrange.

		//    var codeAssist = new Mock<IHQLCodeAssist>();
		//    var completionSource = new CompletionSource(buffer.Object,
		//                                                codeAssist.Object,
		//                                                new Mock<ITextStructureNavigatorSelectorService>().Object);

		//    var completionSets = new List<CompletionSet>();
		//    completionSource.AugmentCompletionSession(session.Object, completionSets);
		//    completionSets.First().ApplicableTo.GetSpan(snapshot).Satisfy(sp => sp.Start == 819 && sp.Length == 0);
		//}

		//[Test]
		//public void WhenCursorHasWordInFrontThenTrackingSpanStartInSamePositionAndEndsWithWorld()
		//{
		//    var snapshot = SnapshotUtil.CreateSnapshot(ExampleForIntellisense);
		//    var buffer = new Mock<ITextBuffer>();
		//    var session = new Mock<ICompletionSession>();
		//    buffer.Setup(b => b.CurrentSnapshot).Returns(snapshot);
		//    session.Setup(s => s.TextView.Caret.Position)
		//        .Returns(new CaretPosition(new VirtualSnapshotPoint(snapshot, 345), new Mock<IMappingPoint>().Object, PositionAffinity.Successor));

		//    session.Setup(s => s.GetTriggerPoint(buffer.Object).GetPoint(snapshot))
		//        .Returns(SnapshotUtil.CreateSnapshotPoint(snapshot, 345)); // <---Important arrange.

		//    var codeAssist = new Mock<IHQLCodeAssist>();
		//    var completionSource = new CompletionSource(buffer.Object,
		//                                                codeAssist.Object,
		//                                                new Mock<ITextStructureNavigatorSelectorService>().Object);

		//    var completionSets = new List<CompletionSet>();
		//    completionSource.AugmentCompletionSession(session.Object, completionSets);
		//    completionSets.First().ApplicableTo.GetSpan(snapshot).Satisfy(sp => sp.Start.Position == 345 && sp.Length == 3);
		//}
	}
}